package chat.ui;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.border.BevelBorder;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.MatteBorder;
import javax.swing.border.SoftBevelBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

import chat.client.ClientMain;
import chat.client.ClientRequestor;
import chat.user.Message;
import chat.user.MessageCreator;
import chat.user.User;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.Image;
import java.awt.Insets;
import java.awt.ScrollPane;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.*;

public class GroupChatWindow extends JFrame {

	private static JTree groupTree;
	private JButton add_btn, remv_btn, refresh_btn, connect_btn, dcs_btn;
	private int BUTTON_WIDTH = 90;
	int i = 385;
	private ChatPanel chat_panel;
	// private ClientRequestor client;
	public String username;
	private User user = new User(true);
	private JLabel usernameL;
	private Vector<String> group_list = new Vector<String>();
	final private int R = 31;
	final private int G = 31;
	final private int B = 31;
	private JComboBox<String> status_combo; 
	
	public GroupChatWindow() throws Exception {

		new MessageCreator(user);

		Random r = new Random();
		int num = r.nextInt(100);
		user.setUserName(Integer.toString(num));
		
		setTitle("chat v 1.0");
		
		GridBagLayout layout = new GridBagLayout();
		
		setVisible(true);
		setLayout(layout);
		setResizable(true);
		
		JPanel TreeButtonsPanel = new JPanel();
		TreeButtonsPanel.setLayout(new GridBagLayout());
		add(TreeButtonsPanel, 
				new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0,
			       GridBagConstraints.CENTER,
			       GridBagConstraints.BOTH,
			       new Insets(0, 0, 0, 0), 0, 0));
		
		usernameL = new JLabel(user.getUserName());
		TreeButtonsPanel.add(usernameL, 
				new GridBagConstraints(0, 3, 1, 1, 1.0, 1.0,
			     GridBagConstraints.CENTER,
			     GridBagConstraints.BOTH,
			     new Insets(0, 0, 0, 0), 0, 0));
		usernameL.setVisible(true);


		chat_panel = new ChatPanel(user);
		
		this.add(chat_panel,
			      new GridBagConstraints(1, 0, 5, 1, 5.0, 1.0,
						     GridBagConstraints.CENTER,
						     GridBagConstraints.BOTH,
						     new Insets(0, 0, 0, 0), 0, 0));
		chat_panel.setVisible(true);
		
		
		connect_btn = new JButton("CONNECT");
		setButtonFont (connect_btn, "Verdana", Font.BOLD, 8);
		connect_btn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				
				DefaultMutableTreeNode node = (DefaultMutableTreeNode) groupTree.getLastSelectedPathComponent();
				
				if (node!=null){
				
				if (node.getLevel()>1){
					if (!getSelectedGroupName().equalsIgnoreCase(getUser().getUserName())){
						getChat().addContact(getSelectedGroupName());
					} 
				}
				else {
					MessageCreator
					.ConnectGroupRequest(getSelectedGroupName(), user);
				}
				}
			}
		});
		TreeButtonsPanel.add(connect_btn);
		
		TreeButtonsPanel.add(connect_btn, 
				new GridBagConstraints(0, 2, 1, 1, 1.0, -10.0,
			       GridBagConstraints.NORTHWEST,
			       GridBagConstraints.CENTER,
			       new Insets(0, 0, 0, 0), 15, 10));

		add_btn = new JButton("ADD GROUP");
		setButtonFont (add_btn, "Verdana", Font.BOLD, 8);
		add_btn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				requestNewGroup();
			}
		});
		TreeButtonsPanel.add(add_btn,
				new GridBagConstraints(0, 1, 1, 1, 1.0, -10.0,
			       GridBagConstraints.NORTHWEST,
			       GridBagConstraints.CENTER,
			       new Insets(0, 0, 0, 0), 20, 10));
		//add_btn.setBounds(0, 200, BUTTON_WIDTH, 20);
		

		remv_btn = new JButton("REMOVE");
		remv_btn.setEnabled(false);
		setButtonFont (remv_btn, "Verdana", Font.BOLD, 8);
		remv_btn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				MessageCreator.RemoveGroupRequest(user, getSelectedGroupName());
			}
		});
		remv_btn.setBounds(BUTTON_WIDTH, 200, BUTTON_WIDTH, 20);
		TreeButtonsPanel.add(remv_btn,
				new GridBagConstraints(1, 1, 1, 1, 30.0, -10.0,
			       GridBagConstraints.NORTHWEST,
			       GridBagConstraints.CENTER,
			       new Insets(0, 0, 0, 0), 20, 10));
		
		dcs_btn = new JButton("DISCONNECT");
		dcs_btn.setEnabled(true);
		setButtonFont (dcs_btn, "Verdana", Font.BOLD, 8);
		dcs_btn.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				MessageCreator.requestDisconnect(user);
			}
		});
		
		TreeButtonsPanel.add(dcs_btn,
				new GridBagConstraints(1, 2, 1, 1, 30.0, -10.0,
			       GridBagConstraints.NORTHWEST,
			       GridBagConstraints.CENTER,
			       new Insets(0, 0, 0, 0), 15, 10));
		
	/*	private_chat = new JButton("PRIVATE");
		private_chat.setEnabled(false);
		setButtonFont (private_chat, "Verdana", Font.BOLD, 9);
		private_chat.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {

				if (!getSelectedGroupName().equalsIgnoreCase(getUser().getUserName())){
					getChat().getTabbedPanel().addNewTab(getSelectedGroupName());
				}
			}
		});
		private_chat.setBounds(0, 290, BUTTON_WIDTH, 30);
		SoftBevelBorder softborder = new SoftBevelBorder(BevelBorder.RAISED);
		EtchedBorder e = new EtchedBorder(Color.blue, Color.GREEN);
		LineBorder l = new LineBorder(Color.CYAN, 3, true);
		MatteBorder m = new MatteBorder(1, 2, 1, 2, Color.red);
		//Border border = new 
		//private_chat.setBorder(m);
		//private_chat.setBackground(Color.gray);
		p.add(private_chat);
*/		
		status_combo = new JComboBox<String>();
		
		status_combo.addItem("Online");
		status_combo.addItem("Busy");
		status_combo.addItem("Do Not Disturb");
		status_combo.addItem("Offline");
		
		Font font = new Font("Verdana", Font.BOLD, 9);
		status_combo.setFont(font);
		
		status_combo.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
			
			switch (status_combo.getSelectedIndex()){
			
			case 0:
				GroupTreeNode tree_node = getNode(user.getUserName());
				tree_node.setFlagIcon("ONLINE");
				user.setStatus("ONLINE");
				MessageCreator.requestUserStatusUpdate(user);
				break;
			case 1:
				GroupTreeNode tree_node1 = getNode(user.getUserName());
				tree_node1.setFlagIcon("BUSY");
				user.setStatus("BUSY");
				MessageCreator.requestUserStatusUpdate(user);
				break;
			case 2:
				GroupTreeNode tree_node2 = getNode(user.getUserName());
				tree_node2.setFlagIcon("DND");
				user.setStatus("DND");
				MessageCreator.requestUserStatusUpdate(user);
				break;
			case 3:
				//user.setStatus(OFFLINE);
				break;
			}
			treeReload();
			}
		});
		
	//	status_combo.setBounds(50, 323, 100, 20);
		TreeButtonsPanel.add(status_combo,
				new GridBagConstraints(0, 4, 1, 1, 1.0, 2.0,
			       GridBagConstraints.SOUTHWEST,
			       GridBagConstraints.CENTER,
			       new Insets(0, 0, 0, 0), 0, 0));
		
		DefaultMutableTreeNode top = new DefaultMutableTreeNode("ROOT");
		groupTree = new JTree(top);

		groupTree.setRootVisible(false);
		groupTree.setCellRenderer(new MyTreeCellRenderer());
		

		JScrollPane sc = new JScrollPane(groupTree);
		//sc.setBounds(0, 0, 100, 100);
		TreeButtonsPanel.add(sc, new GridBagConstraints(0, 0, 2, 1, 1.0, 2.0,
			     GridBagConstraints.CENTER,
			     GridBagConstraints.BOTH,
			     new Insets(0, 0, 0, 0), 0, 0));

		//p.setBounds(0, 0, 180, 200);

		groupTree.addTreeSelectionListener(new TreeSelectionListener() {

			@Override
			public void valueChanged(TreeSelectionEvent arg0) {

				Object obj = groupTree.getLastSelectedPathComponent();
				DefaultMutableTreeNode node = (DefaultMutableTreeNode) obj;

				if (node != null) {

					if (node.getLevel()<2) {

						if (node.toString().equalsIgnoreCase(user.getRelatedGroup())){
							connect_btn.setEnabled(false);
						}
						else {
							connect_btn.setEnabled(true);
						}
						remv_btn.setEnabled(true);
						//private_chat.setEnabled(false);
					}
					else {
						connect_btn.setEnabled(false);
						remv_btn.setEnabled(false);
						if (!node.toString().equalsIgnoreCase(user.getUserName())){
							//private_chat.setEnabled(true);
							connect_btn.setEnabled(true);
						}
					}
					}
			}
		});
		
		groupTree.addMouseListener(new MouseAdapter() {
			
			public void mousePressed(MouseEvent e){
				
				Object obj = groupTree.getLastSelectedPathComponent();
				DefaultMutableTreeNode node = (DefaultMutableTreeNode) obj;
				
				if (e.getClickCount()==2){
					if (node.getLevel()>1&&!node.toString().equalsIgnoreCase(getUser().getUserName())){
						getChat().addContact(getSelectedGroupName());
					}
				}
			}
		});
		
		MessageCreator.AuthRequest(user);
		
		this.group_list.add("ROOT");

		new Thread(new ClientMain(this)).start();

		setSize(new Dimension (800,600));
		setLocation(600, 400);
	}

	public synchronized void addUserItem(String group_name, User user) {

		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();

		GroupTreeNode c_user = new GroupTreeNode(user.getUserName(), user.getStatus());
		
		// int nodes_count = groupTree.getRowCount();
		
		int nodes_count = root.getChildCount();
		
		boolean flag = false;
		
		for (int i = 0; i < nodes_count; i++) {

			String node_name = model.getChild(root, i).toString();

			if (group_name.equalsIgnoreCase(node_name)) {

				Object obj = model.getChild(root, i);

				DefaultMutableTreeNode sel = (DefaultMutableTreeNode) obj;

				for (int j = 0; j < sel.getChildCount(); j++) {
					
					String child_name = sel.getChildAt(j).toString();
					
					if (child_name.equalsIgnoreCase(user.getUserName())){
						
						flag = true;
					}
					
				}
				if ((sel.getLevel() >= 1)&&!flag) {
					
					DefaultMutableTreeNode tmp = new DefaultMutableTreeNode(
							c_user);
					
					model.insertNodeInto(tmp, sel, sel.getChildCount());
					
					flag = false;
				}
				
				treeReload();
			}
		}
	}
	
	public synchronized void removeUserItem (String group_name, String user_name){
		
		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();

		int nodes_count = root.getChildCount();
		
		for (int i = 0; i < nodes_count; i++) {

			String node_name = model.getChild(root, i).toString();

			if (group_name.equalsIgnoreCase(node_name)) {

				Object obj = model.getChild(root, i);

				DefaultMutableTreeNode sel = (DefaultMutableTreeNode) obj;
				
				for (int j=0; j<sel.getChildCount(); j++){
					
					Object child_obj = model.getChild(sel, j);
					
					DefaultMutableTreeNode child = (DefaultMutableTreeNode) child_obj;
					
					if (child.toString().equalsIgnoreCase(user_name)){
						
						model.removeNodeFromParent(child);
					}
				}
			}
		}
	}
	
	public void requestNewGroup() {

		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		// Object obj = groupTree.getLastSelectedPathComponent();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
		// int nodes_count = groupTree.getRowCount();

		int nodes_count = root.getChildCount();

		/*
		 * if(obj!=null) { DefaultMutableTreeNode sel =
		 * (DefaultMutableTreeNode)obj;
		 * 
		 * //Adding more deeper branches
		 * 
		 * /* if(sel.getLevel()>=1) { DefaultMutableTreeNode tmp = new
		 * DefaultMutableTreeNode("Deep"); model.insertNodeInto(tmp, sel,
		 * sel.getChildCount()); }
		 */

		// if(sel.isRoot()) {

		String ask = JOptionPane.showInputDialog("Enter group name");

		boolean isGroupAlreadyExist = false;

		if (ask != null) {

			if (nodes_count > 1) {

				for (int i = 0; i < nodes_count - 1; i++) {

					String node_name = model.getChild(root, i).toString();

					if (ask.equalsIgnoreCase(node_name)) {

						isGroupAlreadyExist = true;
					}
				}
				if (!isGroupAlreadyExist) {

					DefaultMutableTreeNode tmp = new DefaultMutableTreeNode(ask);
					// model.insertNodeInto(tmp, root,
					// model.getChildCount(root));

					MessageCreator.RequestNewGroup(ask, user);

					isGroupAlreadyExist = false;
				} else {

					final ImageIcon icon = new ImageIcon("red1.jpg");
					JOptionPane.showMessageDialog(null,
							"Group is already exist", "Error",
							JOptionPane.INFORMATION_MESSAGE, icon);
				}
			} else {

				DefaultMutableTreeNode tmp = new DefaultMutableTreeNode(ask);
				// model.insertNodeInto(tmp, root, model.getChildCount(root));

				MessageCreator.RequestNewGroup(ask, user);
				
				treeReload();
			}
		}
		// }
		// groupTree.expandPath(new TreePath(sel.getPath()));
	}

	public synchronized void addNewItem(String name) {
		
		treeReload();
		
		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
		
		/*GroupTreeNode g1 = new GroupTreeNode("Test", "red1.jpg");
		
		DefaultMutableTreeNode g = new DefaultMutableTreeNode(g1);
		root.add(g);*/
		
		// int nodes_count = groupTree.getRowCount();

		int nodes_count = root.getChildCount();

		boolean isGroupAlreadyExist = false;

		if (nodes_count > 0) {

			for (int i = 0; i < nodes_count; i++) {

				String node_name = model.getChild(root, i).toString();

				if (name.equalsIgnoreCase(node_name)) {

					isGroupAlreadyExist = true;
				}
			}
			if (!isGroupAlreadyExist) {

				DefaultMutableTreeNode tmp = new DefaultMutableTreeNode(name);
				model.insertNodeInto(tmp, root, (model.getChildCount(root)));
				
				// client.RequestNewGroup(name);

				isGroupAlreadyExist = false;
			}

		} else {

			DefaultMutableTreeNode tmp = new DefaultMutableTreeNode(name);
			model.insertNodeInto(tmp, root, (model.getChildCount(root)));

		}

		treeReload();
	}

	public synchronized void removeItem() {
		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		Object obj = groupTree.getLastSelectedPathComponent();
		if (obj != null) {
			DefaultMutableTreeNode sel = (DefaultMutableTreeNode) obj;

			if (!sel.isRoot()) {
				if (sel.getChildCount() == 0) {

					groupTree.setFocusable(false);
					model.removeNodeFromParent(sel);

				}

				else

					JOptionPane.showMessageDialog(null, "Remove all subnodes");
			}
		}
		
		treeReload();
	}

	public synchronized void removeItem(String name) {

		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();

		// int nodes_count = groupTree.getRowCount();

		int nodes_count = root.getChildCount();

		for (int i = 0; i < nodes_count; i++) {

			String node_name = model.getChild(root, i).toString();

			MutableTreeNode node = (MutableTreeNode) model.getChild(root, i);

			if (name.equalsIgnoreCase(node_name)) {

				model.removeNodeFromParent(node);
				break;

			}
		}
		
		treeReload();
	}

	public Vector<String> getGroupList() {

		Vector<String> group_list = new Vector<String>();
		group_list.add("ROOT");

		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();

		int nodes_count = root.getChildCount();

		// if root is visible nodes count should be *(nodes_count - 1)

		for (int i = 0; i < nodes_count; i++) {

			try {

				String node_name = model.getChild(root, i).toString();
				group_list.add(node_name);
			} catch (ArrayIndexOutOfBoundsException e) {

				e.printStackTrace();
			}

		}

		return group_list;
	}

	public void displayChatWindow() {

		chat_panel.setVisible(true);

	}

	public ChatPanel getChat() {
		return this.chat_panel;
	}

	public User getUser() {
		return this.user;
	}

	public void setUser(User u) {

		this.user = u;
	}

	public String getSelectedGroupName() {

		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		Object obj = groupTree.getLastSelectedPathComponent();
		String node_name = obj.toString();

		return node_name;
	}
	
	public GroupTreeNode getNode(String node_name) {
	
		GroupTreeNode tree_node = null;
		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
		
		int nodes_count = root.getChildCount();
		boolean flag = false;
		
		for (int i = 0; i < nodes_count; i++) {

			String node= model.getChild(root, i).toString();
			Object obj = model.getChild(root, i);
			DefaultMutableTreeNode sel = (DefaultMutableTreeNode) obj;

				for (int j = 0; j < sel.getChildCount(); j++) {
					
					Object child_obj = model.getChild(sel, j);
					DefaultMutableTreeNode child = (DefaultMutableTreeNode) child_obj;
					
					if (child.toString().equalsIgnoreCase(node_name)){
						
						tree_node = (GroupTreeNode) child.getUserObject();
					}
					
				}
		}
		return tree_node;
	}
	
	public void setButtonFont(JButton button, String font_style, int style, int size){
		
		Font font = new Font(font_style, style, size);
		button.setFont(font);
		button.setForeground(new Color(R, G, B));
	}
	
	public void treeReload(){
		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
		model.reload();
		
		for (int row=0; row<groupTree.getRowCount(); row++){
				groupTree.expandRow(row);					
			
	}
}
	
	public void treeReload1(){
		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
		TreePath rootPath = new TreePath(root);
		groupTree.expandPath(rootPath);
		model.reload();
		setExpandedState("General", true);
		
		for (int row=0; row<groupTree.getRowCount(); row++){
				
				DefaultMutableTreeNode node = (DefaultMutableTreeNode) model.getChild(root, row);
				
				Object path = node.getPath();
				
				boolean flag = groupTree.isExpanded(new TreePath(path));
				
				if (flag){
					
					groupTree.expandRow(row);					
				}
		}
		model.reload();
		
		
	}
	
	public void treeReload2(){
		
		DefaultTreeModel model = (DefaultTreeModel) groupTree.getModel();
		model.reload();
		
		Enumeration en = saveExpansionState(groupTree);
		loadExpansionState(groupTree, en);
		
	}
	
	public static Enumeration saveExpansionState(JTree tree) {

        return tree.getExpandedDescendants(new TreePath(tree.getModel().getRoot()));

    }
	
	public static void loadExpansionState(JTree tree, Enumeration enumeration) {

        if (enumeration != null) {

            while (enumeration.hasMoreElements()) {

                TreePath treePath = (TreePath) enumeration.nextElement();

                tree.expandPath(treePath);

            }

        }
	}
	private void setExpandedState(String id, boolean expand)  
    {  
        DefaultMutableTreeNode root = (DefaultMutableTreeNode)groupTree.getModel().getRoot();  
        Enumeration e = root.breadthFirstEnumeration();  
        while(e.hasMoreElements())  
        {  
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement();  
            if(node.toString().equalsIgnoreCase(id))  
            {  
                TreePath path = new TreePath(node.getPath());  
                expandNode(path, expand);  
                break;  
            }  
        }  
    }
	private void expandNode(TreePath parent, boolean expand)  
    {  
        TreeNode node = (TreeNode)parent.getLastPathComponent();  
        if (node.getChildCount() >= 0)  
        {  
            Enumeration e = node.children();  
            while(e.hasMoreElements())  
            {  
                TreeNode n = (TreeNode)e.nextElement();  
                TreePath path = parent.pathByAddingChild(n);  
                expandNode(path, expand);  
            }  
        }  
        if(expand)  
        	groupTree.expandPath(parent);  
        else  
        	groupTree.collapsePath(parent);  
    }  
	
	public ChatPanel getChatPanel(){
		return this.chat_panel;
	}
}